#include <iostream>
#include <list>
#include "aiPlayer.h"

using namespace std;

AIPlayer::AIPlayer(void)
: color(1), diff(0), known(0, Piece())
{
	clearTrack();
}

void AIPlayer::clearTrack()
{
	for (int i=0; i<10; i++)
	{
		for (int j=0; j<10; j++)
		{
			for (int k=0; k<4; k++)
			{
				track[i][j][k] = 0;
			}
		}
	}
}

void AIPlayer::setColor(int newColor)
{
	color = newColor;
	return;
}

void AIPlayer::setDiff(int newDiff)
{
	diff = newDiff;
	return;
}

void AIPlayer::clearKnown(void)
{
	known.clear();
	return;
}

void AIPlayer::setup(Board &gameBoard)
{
	int numIter[12] = {1,1,1,2,3,4,4,4,5,8,6,1};
	int i, j, row = 9, col = 9;
	for(i = 0; i < 12; i++) {
		for(j = 0; j < numIter[i]; j++) {
			gameBoard.setPiece(Posit(row, col), Piece(i, 1, false));
			col--;
			if(col == -1) {
				col = 9;
				row--;
			}
		}
	}
	gameBoard.printAll();
	return;
}

void AIPlayer::populateRest(Board &gameBoard, int left[])
{
	int row, col;
	// For 0-11
	for (int i=0; i<12; i++)
	{
		while(left[i])
		{
			do
			{
				row = rand()%4+6;
				col = rand()%10;
			} while (gameBoard.getPiece(row,col).getRank() >= 0);
			gameBoard.setPiece(Posit(row,col), Piece(i, 1, false));
			left[i]--;
		}
	}
	// For all left
	// Choose random spot (6-9, 0-9)
	// If not empty, fill
}

void AIPlayer::simpleAI(Board &gameBoard)
{
	int select, endcol, endrow, row, col, i, j, direction;
	Posit start, end, temp;
	vector<Posit> possibles;
	clearTrack();

	for (i=0; i<10; i++)
	{
		for (j=0; j<10; j++)
		{
			if (gameBoard.getPiece(i,j).getOwner()==1 && gameBoard.getPiece(i,j).getRank() < 10)
			{

				if (i<9)
				{
					if (gameBoard.getPiece(i+1,j).getRank()==-1 || (gameBoard.getPiece(i+1,j).getRank()>gameBoard.getPiece(i,j).getRank() && gameBoard.getPiece(i+1,j).getOwner()==0))
					{
						temp.setRow(i);
						temp.setCol(j);
						possibles.push_back(temp);
						track[i][j][0] = 1;
					}
				}
				if (j<9)
				{
					if (gameBoard.getPiece(i,j+1).getRank()==-1 || (gameBoard.getPiece(i,j+1).getRank()>gameBoard.getPiece(i,j).getRank() && gameBoard.getPiece(i,j+1).getOwner()==0))
					{
						temp.setRow(i);
						temp.setCol(j);
						possibles.push_back(temp);
						track[i][j][1] = 1;
					}
				}
				if (i>0)
				{
					if (gameBoard.getPiece(i-1,j).getRank()==-1 || (gameBoard.getPiece(i-1,j).getRank()>gameBoard.getPiece(i,j).getRank() && gameBoard.getPiece(i-1,j).getOwner()==0))
					{
						temp.setRow(i);
						temp.setCol(j);
						possibles.push_back(temp);
						track[i][j][2] = 1;
					}
				}
				if (j>0)
				{
					if (gameBoard.getPiece(i,j-1).getRank()==-1 || (gameBoard.getPiece(i,j-1).getRank()>gameBoard.getPiece(i,j).getRank() && gameBoard.getPiece(i,j-1).getOwner()==0))
					{
						temp.setCol(j);
						possibles.push_back(temp);
						track[i][j][3] = 1;
					}
				}
			}

		}
	}
	do {
		select = rand()%possibles.size();
		for(i=0;i<4;i++) {
			if(track[possibles.at(select).getRow()][possibles.at(select).getCol()][i] == 1) {
				direction = i;
			}
		}
		switch(direction) {
			case 0:
				i = 1;
				j = 0;
				break;
			case 1:
				j = 1;
				break;
			case 2:
				i = -1;
				j = 0;
				break;
			case 3:
				i = 0;
				j = -1;
				break;
		}
		start.setRow(possibles.at(select).getRow());
		start.setCol(possibles.at(select).getCol());
		end.setRow(possibles.at(select).getRow() + i);
		end.setCol(possibles.at(select).getCol() + j);
	} while(!gameBoard.movePiece(1,start,end));
}

void AIPlayer::aiSetup(Board &gameBoard, int strategy)
{
	int left[12] = {1,1,1,2,3,4,4,4,5,8,6,1};
 	int rnum;
	srand((unsigned)time(0));
	int srow, scol, temprow, tempcol;
	int numIter[12] = {1,1,1,2,3,4,4,4,5,8,6,1};
	int i, j, row = 9, col = 9;
	switch(strategy)
	{
		case 0:

			for(i = 0; i < 12; i++)
			{
				for(j = 0; j < numIter[i]; j++)
				{
					gameBoard.setPiece(Posit(row, col), Piece(i, 1, false));
					col--;
					if(col == -1)
					{
						col = 9;
						row--;
					}
				}	
			}
			break;
		case 1:		// The Cyclone Defense
			// 1) Place flag in row 8 or 7 (50/50) and surround with bombs
				if (rand()%2) srow = 8;
				else srow = 7;
				scol = (rand()%8) + 1; // Columns 1-8
				gameBoard.setPiece(Posit(srow,scol), Piece(11, 1, false));	// Place the flag at srow, scol

				left[11]--;

				// Surround with bombs
				gameBoard.setPiece(Posit(srow-1,scol), Piece(10,1, false));
				gameBoard.setPiece(Posit(srow,scol+1), Piece(10,1, false));
				gameBoard.setPiece(Posit(srow+1,scol), Piece(10,1, false));
				gameBoard.setPiece(Posit(srow,scol-1), Piece(10,1, false));

				left[10]-=4;

			// 2) Put miners (8) in 6 (40) 7 (40) or 8 (20)
				while (left[8])
				{
					rnum = rand()%10+1;
					if (rnum<4)
					{
						do	// Find a column without any pieces in row 6
						{
							tempcol = rand()%10;
						} while (gameBoard.getPiece(6,tempcol).getRank() >= 0);

						gameBoard.setPiece(Posit(6, tempcol), Piece(8, 1, false));		///****Perhaps having setPiece return -1 if piece already there


					} else if (rnum<8)
					{
						do	// Find a column without any pieces in row 7
						{
							tempcol = rand()%10;
						} while (gameBoard.getPiece(8, tempcol).getRank() >= 0);
						gameBoard.setPiece(Posit(8, tempcol), Piece(8, 1, false));		///****Perhaps having setPiece return -1 if piece already there


					} else {
						do	// Find a column without any pieces in row 8
						{
							tempcol = rand()%10;
						} while (gameBoard.getPiece(8, tempcol).getRank() >= 0);
						gameBoard.setPiece(Posit(8, tempcol), Piece(8, 1, false));		///****Perhaps having setPiece return -1 if piece already there


					}
					left[8]--;
				}

			// 3) Put remaining 2 bombs in 9 or 8 (50/50)
				while(left[10])
				{
					do
					{
						rnum = rand()%2;
						if (rnum) temprow = 9;
						else temprow = 8;
						tempcol = rand()%10;
					} while (gameBoard.getPiece(temprow,tempcol).getRank() >= 0 );
					gameBoard.setPiece(Posit(temprow,tempcol), Piece(10,1, false));


					left[10]--;
				}

			// 4) Put all but 2 scouts in 9 or 8 (80/20)
				while(left[9]-2)
				{
					do
					{
						rnum = rand()%10+1;
						if (rnum<8) temprow = 9;
						else temprow = 8;
						tempcol = rand()%10;
					} while (gameBoard.getPiece(temprow,tempcol).getRank() >= 0);
					gameBoard.setPiece(Posit(temprow,tempcol), Piece(9,1, false));


					left[9]--;
				}

			// 5) Populate rest

			populateRest(gameBoard, left);

			break;

		case 2:         // The Tempest Defense

		  // 1) Put flag in row 9, col 1-8 with bombs surrounding
			scol = (rand()%8) + 1;
			gameBoard.setPiece(Posit(9, scol), Piece(11,1, false));
			left[11]--;
			gameBoard.setPiece(Posit(9, scol-1), Piece(10,1, false));
			gameBoard.setPiece(Posit(9, scol+1), Piece(10,1, false));
			gameBoard.setPiece(Posit(8, scol), Piece(10,1, false));
			left[10] -= 3;

			// 2) Put high ranks (1,2,3,4) in rows 6, 7 (60/40)
			for (int i=1; i<5; i++)
			{
				while(left[i])
				{
					do
					{
						if (rand()%10 < 6) srow = 6;
						else srow = 7;
						scol = rand()%10;
					} while(gameBoard.getPiece(srow, scol).getRank() >= 0);

					gameBoard.setPiece(Posit(srow,scol), Piece(i,1,false));
					left[i]--;
				}
			}

			// 3) Fill holes in rows 6,7 with low ranks 9 and 8 (50/50)

			for (int i=8; i<10; i++)
			{
				while(left[i])
				{
					do
					{
						srow = rand()%2 + 6;
						scol = rand()%10;
					} while(gameBoard.getPiece(srow, scol).getRank() >= 0);
					gameBoard.setPiece(Posit(srow,scol), Piece(i,1,false));
					left[i]--;
				}
			}
			                
			// 4) Populate rest
			populateRest(gameBoard, left);
      break;

		case 3:         // Shoreline Bluff variation
		  // 1) Put flag in row 6, col 2,3,6,or7 and surround with bombs
			srow = 6;
			rnum = rand()%4;
			switch(rnum)
			{
				case 0:	scol = 2;
					break;
				case 1:	scol = 3;
					break;
				case 2:	scol = 6;
					break;
				case 3:	scol = 7;
					break;
			}

			// place flag
			gameBoard.setPiece(Posit(srow, scol), Piece(11,1, false));
			left[11]--;
			// place 3 bombs
			gameBoard.setPiece(Posit(srow, scol-1), Piece(10,1, false));	// left
			gameBoard.setPiece(Posit(srow, scol+1), Piece(10,1, false));	// right
			gameBoard.setPiece(Posit(srow+1, scol), Piece(10,1, false));	// below
			left[10] -= 3;

			

			// 2) Put all high ranks (1,2,3,4) in row 7
			for (int i=1; i<5; i++)
			{
				while(left[i])
				{
					do
					{
						srow = 7;
						scol = rand()%10;
					} while(gameBoard.getPiece(srow, scol).getRank() >= 0);
					gameBoard.setPiece(Posit(srow,scol), Piece(i,1,false));
					left[i]--;
				}
			}

			// 3) Fill the middle space with bombs on row 6
			if (!gameBoard.getPiece(6,4).getRank()>=0)
			{
				gameBoard.setPiece(Posit(6,4), Piece(10,1,false));
				left[10]--;
			}
			if (!gameBoard.getPiece(6,5).getRank()>=0)
			{
				gameBoard.setPiece(Posit(6,5), Piece(10,1,false));
				left[10]--;
			}

			// 4) Put a bomb in row 7

			do
			{
				srow = 7;
				scol = rand()%10;
			} while(gameBoard.getPiece(srow,scol).getRank()>=0);
			gameBoard.setPiece(Posit(srow,scol), Piece(10,1,false));
			left[10]--;

			// 5) Fill row 6 with scouts (9s)
				// get the number of open spaces
			rnum = 0;
			for (int i=0; i<10; i++) if (gameBoard.getPiece(6,i).getRank()>=0) rnum++;
			for (int i=0; i<(10-rnum); i++)
			{
				do
				{
					srow = 6;
					scol = rand()%10;
				} while(gameBoard.getPiece(srow,scol).getRank()>=0);
				gameBoard.setPiece(Posit(srow,scol), Piece(9,1,false));
				left[9]--;
			}

			// 4) Populate rest
			populateRest(gameBoard, left);
      break;

	}

}



double AIPlayer::calcUnknowns(Board &gameBoard)
{
	list<Piece>::iterator it;
	int totalRank = 205;
//	bombs = 6;
	for(it = gameBoard.userLost.begin(); it != gameBoard.userLost.end(); it++)
	{
		totalRank -= it->getRank();
	}
	return (double)totalRank/(double)(38-gameBoard.userLost.size());
}

void AIPlayer::handleKnownOpp(Board &gameBoard, int row, int col, int oRow, int oCol, int dir)
{
	if (gameBoard.getPiece(oRow,oCol).getRank()==11) track[row][col][dir] = 100000;	// If adj to flag, infinitely prefer
	else if (gameBoard.getPiece(row,col).getRank()==0 && gameBoard.getPiece(oRow,oCol).getRank()==1) track[row][col][dir] = 20000;	// Else if spy is adj to marshal, prefer
	else if (gameBoard.getPiece(row,col).getRank()==0) track[row][col][dir] = 1;	// Else if spy is adj anyone else, avoid
	else if (gameBoard.getPiece(row,col).getRank()==8 && gameBoard.getPiece(oRow,oCol).getRank()==10) track[row][col][dir] = 5000;	// Else if miner is adj to bomb, prefer
	else if (gameBoard.getPiece(oRow,oCol).getRank()==10) track[row][col][dir] = 1;	// Else if someone else is adj to bomb, avoid
	else if (gameBoard.getPiece(oRow,oCol).getRank()==0) track[row][col][dir] = 5000;	// Else if anyone is adjacent to a spy, prefer
	else if (gameBoard.getPiece(row,col).getRank()<gameBoard.getPiece(oRow,oCol).getRank()) track[row][col][dir]=1000;	// Else if adjacent piece is weaker
	else if (gameBoard.getPiece(row,col).getRank()==gameBoard.getPiece(oRow,oCol).getRank()) track[row][col][dir]=5;	// Else if adjacent piece is equal, try to avoid
	else if (gameBoard.getPiece(row,col).getRank()>gameBoard.getPiece(oRow,oCol).getRank()) track[row][col][dir]=1;	// Else if adjacent piece is stronger, try to avoid
	else track[row][col][dir]=1;	// This should never happen
}

void AIPlayer::makeMove(Board &gameBoard)
{
	int max=-1, secondmax=-1, select, endrow, endcol, choose, i, j, k;
	vector<Posit> possibles, spossibles;

	findMoves(gameBoard);

	for (i=0; i<10; i++)
	{
		for (j=0; j<10; j++)
		{
			for (k=0; k<4; k++)
			{
				if (track[i][j][k]>max)
				{
					if (max>0) secondmax = max;
					max = track[i][j][k];
				}
			}
		}
	}

	for (i=0; i<10; i++)
	{
		for (j=0; j<10; j++)
		{
			for (k=0; k<4; k++)
			{
				if (track[i][j][k]==max)
				{
					Posit temp(i,j);
					possibles.push_back(temp);
				} else if (track[i][j][k]==secondmax && secondmax>0)
				{
					Posit temp(i,j);
					spossibles.push_back(temp);
				}
			}
		}
	}
	// If possible moves
	if (possibles.size()||spossibles.size())
	{
		// Of the 2 types of best moves, pick one favoring the higher
		select = rand()%possibles.size();
		choose = rand()%(max+secondmax);
		if (choose>max)
		{
			select = rand()%spossibles.size();
			Posit start(spossibles[select].getRow(), spossibles[select].getCol());
			for (i=0; i<4; i++)
			{
				if (track[spossibles[select].getRow()][spossibles[select].getCol()][i]==secondmax)
				{
					if (i==0)
					{
						endrow = spossibles[select].getRow()+1;	// Move Up
						endcol = spossibles[select].getCol();
					} else if (i==1)
					{
						endrow = spossibles[select].getRow();	// Move Right
						endcol = spossibles[select].getCol()+1;
					} else if (i==2)
					{
						endrow = spossibles[select].getRow()-1;	// Move Down
						endcol = spossibles[select].getCol();
					} else if (i==3){
						endrow = spossibles[select].getRow();	// Move Left
						endcol = spossibles[select].getCol()-1;
					}
				}
			}
			Posit end(endrow, endcol);
			gameBoard.movePiece(1, start, end);
		} else
		{
			select = rand()%possibles.size();
			Posit start(possibles[select].getRow(), possibles[select].getCol());

			for (i=0; i<4; i++)
			{
				if (track[possibles[select].getRow()][possibles[select].getCol()][i]==max)
				{

					if (i==0)
					{
						endrow = possibles[select].getRow()+1;	// Move Up
						endcol = possibles[select].getCol();
					} else if (i==1)
					{
						endrow = possibles[select].getRow();	// Move Right
						endcol = possibles[select].getCol()+1;
					} else if (i==2)
					{
						endrow = possibles[select].getRow()-1;	// Move Down
						endcol = possibles[select].getCol();
					} else if (i==3){
						endrow = possibles[select].getRow();	// Move Left
						endcol = possibles[select].getCol()-1;
					}
				}
			}
			Posit end(endrow, endcol);
			// show the previous move	
			if(start.getCol() == end.getCol()) {
				i = start.getRow();
				if(i > end.getRow()) {
					while(i != end.getRow()) {
						mvprintw(40 - i*4, 4 + start.getCol()*8 + 20, "\\/");
						i--;
					}
				} else {
					while(i != end.getRow()) {
						mvprintw(36 - i*4, 4 + start.getCol()*8 + 20, "/\\");
						i++;
					}
				}
			} else {
				i = start.getCol();
				if(i > end.getCol()) {
					while(i != end.getCol()) {
						mvprintw(38 - start.getRow()*4, i*8 + 20, "<-");
						i--;
					}
				} else {
					while(i != end.getCol()) {
						mvprintw(38 - start.getRow()*4, 8 + i*8 + 20, "->");
						i++;
					}
				}
			}
			gameBoard.movePiece(1, start, end);
		}

	}
}

void AIPlayer::findMoves(Board &gameBoard)
{
	int row, col, i, j;
	double unknown;
	clearTrack();		// Clear the track array
//	calcUnknown(gameBoard);	// Average the known pieces
	
	// For every piece on the board
	for (i=0; i<10; i++)
	{
		for (j=0; j<10; j++)
		{
			// If the computer owns it AND it is not a flag AND it is not a bomb
			if (gameBoard.getPiece(i,j).getOwner()==1 && gameBoard.getPiece(i,j).getRank()!=10 && gameBoard.getPiece(i,j).getRank()!=11) // If the piece is the computer's
			{
				// If it is surrounded by an open space setprefs
				if (i<9){
					if (gameBoard.getPiece(i+1,j).getRank()==-1) track[i][j][0] = 10;	// Up preference for no piece is 1
				}
				if (j<9)
				{
					if (gameBoard.getPiece(i,j+1).getRank()==-1) track[i][j][1] = 20;	// Right preference for no piece is 2
				}
				if (i>0){
					if (gameBoard.getPiece(i-1,j).getRank()==-1) track[i][j][2] = 40;	// Down preference for no piece is 4
				}
				if (j>0){
					if (gameBoard.getPiece(i,j-1).getRank()==-1) track[i][j][3] = 20;	// Left preference for no piece is 2
				}

			if (i<9)
			{	
				if (gameBoard.getPiece(i+1,j).getRank()>=0 && gameBoard.getPiece(i+1,j).getOwner()==0)			// If opponent is above
				{
					// If opponent is known
					if (gameBoard.getPiece(i+1,j).getKnown() == true)
					{
						handleKnownOpp(gameBoard, i, j, i+1, j, 0);
					} else {			
						// If opponent is unknown
						unknown = calcUnknowns(gameBoard);
						if (gameBoard.getPiece(i,j).getRank() == 0) {
							track[i][j][0] = 1;
						} else if (gameBoard.getPiece(i,j).getRank() == 9) {
							track[i][j][0] = 100;
						} else if (gameBoard.getPiece(i,j).getRank()<unknown) {
							track[i][j][0] = 50;
						} else {
							track[i][j][0] = 30;
						}
					}

				}
			}
			if (j<9)
			{
				if (gameBoard.getPiece(i,j+1).getRank()>=0 && gameBoard.getPiece(i,j+1).getOwner()==0)			// If opponent is right
				{
					if (gameBoard.getPiece(i,j+1).getKnown() == true)
					{
						handleKnownOpp(gameBoard, i, j, i, j+1, 1);
					} else {
						unknown = calcUnknowns(gameBoard);
						if (gameBoard.getPiece(i,j).getRank() == 0) {
							track[i][j][1] = 1;
						} else if (gameBoard.getPiece(i,j).getRank() == 9) {
							track[i][j][1] = 100;
						} else if (gameBoard.getPiece(i,j).getRank()<unknown) {
							track[i][j][1] = 50;
						} else {
							track[i][j][1] = 30;
						}
					}
				}
			}
			if (i>0)
			{
				if (gameBoard.getPiece(i-1,j).getRank()>=0 && gameBoard.getPiece(i-1,j).getOwner()==0)			// If opponent is down
				{
					if (gameBoard.getPiece(i-1,j).getKnown() == true)
					{
						handleKnownOpp(gameBoard, i, j, i-1, j, 2);
					} else {
						unknown = calcUnknowns(gameBoard);
						if (gameBoard.getPiece(i,j).getRank() == 0) {
							track[i][j][2] = 1;
						} else if (gameBoard.getPiece(i,j).getRank() == 9) {
							track[i][j][2] = 100;
						} else if (gameBoard.getPiece(i,j).getRank()<unknown) {
							track[i][j][2] = 50;
						} else {
							track[i][j][2] = 30;
						}
					}
				}
			}
			if (j>0)
			{
				if (gameBoard.getPiece(i,j-1).getRank()>=0 && gameBoard.getPiece(i,j-1).getOwner()==0 && j>0)			// If opponent is left
				{
					if (gameBoard.getPiece(i,j-1).getKnown() == true)
					{
						handleKnownOpp(gameBoard, i, j, i, j-1, 3);
					} else {
						unknown = calcUnknowns(gameBoard);
						if (gameBoard.getPiece(i,j).getRank() == 0) {
							track[i][j][3] = 1;
						} else if (gameBoard.getPiece(i,j).getRank() == 9) {
							track[i][j][3] = 100;
						} else if (gameBoard.getPiece(i,j).getRank()<unknown) {
							track[i][j][3] = 50;
						} else {
							track[i][j][3] = 30;
						}
					}
				}
			}

			}
		}
	}
}

